home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.004 / xemacs-1 / xemacs-19.13 / src / sgiplay.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-05  |  18.7 KB  |  730 lines

  1. /* Play sound using the SGI audio library
  2.    written by Simon Leinen <simon@lia.di.epfl.ch>
  3.    Copyright (C) 1992 Free Software Foundation, Inc.
  4.  
  5. This file is part of XEmacs.
  6.  
  7. XEmacs is free software; you can redistribute it and/or modify it
  8. under the terms of the GNU General Public License as published by the
  9. Free Software Foundation; either version 2, or (at your option) any
  10. later version.
  11.  
  12. XEmacs is distributed in the hope that it will be useful, but WITHOUT
  13. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with XEmacs; see the file COPYING.  If not, write to the Free
  19. Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21. /* Synched up with: Not in FSF. */
  22.  
  23. #include <config.h>
  24. #include "lisp.h"
  25.  
  26. #include <audio.h>
  27. #include <sys/file.h>
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #include <fcntl.h>
  31. #include <string.h>
  32. #include <netinet/in.h>        /* for ntohl() etc. */
  33.  
  34. /* Configuration options */
  35.  
  36. /* ability to parse Sun/NeXT (.au or .snd) audio file headers.  The
  37.    .snd format supports all sampling rates and sample widths that are
  38.    commonly used, as well as stereo.  It is also easy to parse. */
  39. #ifndef HAVE_SND_FILES
  40. #define HAVE_SND_FILES    1
  41. #endif
  42.  
  43. /* support for eight-but mu-law encoding.  This is a useful compaction
  44.    technique, and most sounds from the Sun universe are in this
  45.    format. */
  46. #ifndef HAVE_MULAW_8
  47. #define HAVE_MULAW_8    1
  48. #endif
  49.  
  50. /* if your machine is very slow, you have to use a table lookup to
  51.    convert mulaw samples to linear.  This makes Emacs bigger so try to
  52.    avoid it. */
  53. #ifndef USE_MULAW_DECODE_TABLE
  54. #define USE_MULAW_DECODE_TABLE    0
  55. #endif
  56.  
  57. /* support for linear encoding -- useful if you want better quality.
  58.    This enables 8, 16 and 24 bit wide samples. */
  59. #ifndef HAVE_LINEAR
  60. #define HAVE_LINEAR    1
  61. #endif
  62.  
  63. /* support for 32 bit wide samples.  If you notice the difference
  64.    between 32 and 24 bit samples, you must have very good ears.  Since
  65.    the SGI audio library only supports 24 bit samples, each sample has
  66.    to be shifted right by 8 bits anyway.  So you should probably just
  67.    convert all your 32 bit audio files to 24 bit. */
  68. #ifndef HAVE_LINEAR_32
  69. #define HAVE_LINEAR_32    0
  70. #endif
  71.  
  72. /* support for stereo sound.  Imagine the cool applications of this:
  73.    finally you don't just hear a beep -- you also know immediately
  74.    *where* something went wrong! Unfortunately the programming
  75.    interface only takes a single volume argument so far. */
  76. #ifndef HAVE_STEREO
  77. #define HAVE_STEREO    1
  78. #endif
  79.  
  80. /* the play routine can be interrupted between chunks, so we choose a
  81.    small chunksize to keep the system responsive (2000 samples
  82.    correspond to a quarter of a second for .au files.  If you
  83.    HAVE_STEREO, the chunksize should probably be even. */
  84. #define CHUNKSIZE 8000
  85.  
  86. /* the format assumed for header-less audio data.  The following
  87.    assumes ".au" format (8000 samples/sec mono 8-bit mulaw). */
  88. #define DEFAULT_SAMPLING_RATE      8000
  89. #define DEFAULT_CHANNEL_COUNT         1
  90. #define DEFAULT_FORMAT          AFmulaw8
  91.  
  92. /* Exports */
  93.  
  94. /* all compilers on machines that have the SGI audio library
  95.    understand prototypes, right? */
  96.  
  97. extern void play_sound_file (char *, int);
  98. extern void play_sound_data (unsigned char *, int, int);
  99.  
  100. /* Data structures */
  101.  
  102. /* an AudioContext describes everything we want to know about how a
  103.    particular sound snippet should be played.  It is split into three
  104.    parts (device, port and buffer) for implementation reasons.  The
  105.    device part corresponds to the state of the output device and must
  106.    be reverted after playing the samples.  The port part corresponds
  107.    to an ALport; we want to allocate a minimal number of these since
  108.    there are only four of them system-wide, but on the other hand we
  109.    can't use the same port for mono and stereo.  The buffer part
  110.    corresponds to the sound data itself. */
  111.  
  112. typedef struct _AudioContextRec * AudioContext;
  113.  
  114. typedef struct
  115. {
  116.   long        device;
  117.   int        left_speaker_gain;
  118.   int        right_speaker_gain;
  119.   long        output_rate;
  120. }
  121. AudioDeviceRec, * AudioDevice;
  122.  
  123. /* supported sound data formats */
  124.  
  125. typedef enum
  126. {
  127.   AFunknown,
  128. #if HAVE_MULAW_8
  129.   AFmulaw8,
  130. #endif
  131. #if HAVE_LINEAR
  132.   AFlinear8,
  133.   AFlinear16,
  134.   AFlinear24,
  135. #if HAVE_LINEAR_32
  136.   AFlinear32,
  137. #endif
  138. #endif
  139.   AFillegal
  140. }
  141. AudioFormat;
  142.  
  143. typedef struct
  144. {
  145.   ALport    port;
  146.   AudioFormat    format;
  147.   unsigned    nchan;
  148.   unsigned    queue_size;
  149. }
  150. AudioPortRec, * AudioPort;
  151.  
  152. typedef struct
  153. {
  154.   void  *    data;
  155.   unsigned long    size;
  156.   void         (* write_chunk_function) (void *, void *, AudioContext);
  157. }
  158. AudioBufferRec, * AudioBuffer;
  159.  
  160. typedef struct _AudioContextRec
  161. {
  162.   AudioDeviceRec    device;
  163.   AudioPortRec        port;
  164.   AudioBufferRec    buffer;
  165. }
  166. AudioContextRec;
  167.  
  168. #define ac_device        device.device
  169. #define ac_left_speaker_gain    device.left_speaker_gain
  170. #define ac_right_speaker_gain    device.right_speaker_gain
  171. #define ac_output_rate        device.output_rate
  172. #define ac_port            port.port
  173. #define ac_format        port.format
  174. #define ac_nchan        port.nchan
  175. #define ac_queue_size        port.queue_size
  176. #define ac_data            buffer.data
  177. #define ac_size            buffer.size
  178. #define ac_write_chunk_function    buffer.write_chunk_function
  179.  
  180. /* Forward declarations */
  181.  
  182. static Lisp_Object close_sound_file (Lisp_Object);
  183. static AudioContext audio_initialize (unsigned char *, int, int);
  184. static void play_internal (unsigned char *, int, AudioContext);
  185. static void drain_audio_port (AudioContext);
  186. static void write_mulaw_8_chunk (void *, void *, AudioContext);
  187. static void write_linear_chunk (void *, void *, AudioContext);
  188. static void write_linear_32_chunk (void *, void *, AudioContext);
  189. static Lisp_Object restore_audio_port (Lisp_Object);
  190. static AudioContext initialize_audio_port (AudioContext);
  191. static int open_audio_port (AudioContext, AudioContext);
  192. static void adjust_audio_volume (AudioDevice);
  193. static void get_current_volumes (AudioDevice);
  194. static int set_channels (ALconfig, unsigned);
  195. static int set_output_format (ALconfig, AudioFormat);
  196. static int parse_snd_header (void*, long, AudioContext);
  197.  
  198. /* are we looking at an NeXT/Sun audio header? */
  199. #define LOOKING_AT_SND_HEADER_P(address) \
  200.   (!strncmp(".snd", (char *)(address), 4))
  201.  
  202. static Lisp_Object
  203. close_sound_file (closure)
  204.      Lisp_Object closure;
  205. {
  206.   close (XINT (closure));
  207.   return Qnil;
  208. }
  209.  
  210. void
  211. play_sound_file (sound_file, volume)
  212.      char * sound_file;
  213.      int volume;
  214. {
  215.   int count = specpdl_depth ();
  216.   int input_fd;
  217.   unsigned char buffer[CHUNKSIZE];
  218.   int bytes_read;
  219.   AudioContext ac = (AudioContext) 0;
  220.  
  221.   input_fd = open (sound_file, O_RDONLY);
  222.   if (input_fd == -1)
  223.     /* no error message -- this can't happen
  224.        because Fplay_sound_file has checked the
  225.        file for us. */
  226.     return;
  227.  
  228.   record_unwind_protect (close_sound_file, make_number (input_fd));
  229.  
  230.   while ((bytes_read = read (input_fd, buffer, CHUNKSIZE)) > 0)
  231.     {
  232.       if (ac == (AudioContext) 0)
  233.     {
  234.       ac = audio_initialize (buffer, bytes_read, volume);
  235.       if (ac == 0)
  236.         return;
  237.     }
  238.       else
  239.     {
  240.       ac->ac_data = buffer;
  241.       ac->ac_size = bytes_read;
  242.     }
  243.       play_internal (buffer, bytes_read, ac);
  244.     }
  245.   drain_audio_port (ac);
  246.   unbind_to (count, Qnil);
  247. }
  248.  
  249. static long
  250. saved_device_state[] = {
  251.   AL_OUTPUT_RATE, 0,
  252.   AL_LEFT_SPEAKER_GAIN, 0,
  253.   AL_RIGHT_SPEAKER_GAIN, 0,
  254. };
  255.  
  256. static Lisp_Object
  257. restore_audio_port (closure)
  258.      Lisp_Object closure;
  259. {
  260.   Lisp_Object * contents = (vector_data (XVECTOR (closure)));
  261.   saved_device_state[1] = XINT (contents[0]);
  262.   saved_device_state[3] = XINT (contents[1]);
  263.   saved_device_state[5] = XINT (contents[2]);
  264.   ALsetparams (AL_DEFAULT_DEVICE, saved_device_state, 6);
  265.   return Qnil;
  266. }
  267.  
  268. void
  269. play_sound_data (data, length, volume)
  270.      unsigned char * data;
  271.      int length;
  272.      int volume;
  273. {
  274.   int count = specpdl_depth ();
  275.   AudioContext ac;
  276.  
  277.   ac = audio_initialize (data, length, volume);
  278.   if (ac == (AudioContext) 0)
  279.     return;
  280.   play_internal (data, length, ac);
  281.   drain_audio_port (ac);
  282.   unbind_to (count, Qnil);
  283. }
  284.  
  285. static AudioContext
  286. audio_initialize (data, length, volume)
  287.      unsigned char * data;
  288.      int length;
  289.      int volume;
  290. {
  291.   Lisp_Object audio_port_state[3];
  292.   static AudioContextRec desc;
  293.   AudioContext ac;
  294.  
  295.   desc.ac_right_speaker_gain
  296.     = desc.ac_left_speaker_gain
  297.       = volume * 256 / 100;
  298.   desc.ac_device = AL_DEFAULT_DEVICE;
  299.  
  300. #if HAVE_SND_FILES
  301.   if (LOOKING_AT_SND_HEADER_P (data))
  302.     {
  303.       if (parse_snd_header (data, length, & desc)==-1)
  304.     report_file_error ("decoding .snd header", Qnil);
  305.     }
  306.   else
  307. #endif
  308.       {
  309.     desc.ac_data = data;
  310.     desc.ac_size = length;
  311.     desc.ac_output_rate = DEFAULT_SAMPLING_RATE;
  312.     desc.ac_nchan = DEFAULT_CHANNEL_COUNT;
  313.     desc.ac_format = DEFAULT_FORMAT;
  314.     desc.ac_write_chunk_function = write_mulaw_8_chunk;
  315.       }
  316.  
  317.   /* Make sure that the audio port is reset to
  318.      its initial characteristics after exit */
  319.   ALgetparams (desc.ac_device, saved_device_state,
  320.            sizeof (saved_device_state) / sizeof (long));
  321.   audio_port_state[0] = make_number (saved_device_state[1]);
  322.   audio_port_state[1] = make_number (saved_device_state[3]);
  323.   audio_port_state[2] = make_number (saved_device_state[5]);
  324.   record_unwind_protect (restore_audio_port,
  325.              Fvector (3, &audio_port_state[0]));
  326.       
  327.   ac = initialize_audio_port (& desc);
  328.   desc = * ac;
  329.   return ac;
  330. }
  331.  
  332. static void
  333. play_internal (data, length, ac)
  334.      unsigned char * data;
  335.      int length;
  336.      AudioContext ac;
  337. {
  338.   unsigned char * limit;
  339.   if (ac == (AudioContext) 0)
  340.     return;
  341.  
  342.   data = ac->ac_data;
  343.   limit = data + ac->ac_size;
  344.   while (data < limit)
  345.     {
  346.       unsigned char * chunklimit = data + CHUNKSIZE;
  347.  
  348.       if (chunklimit > limit)
  349.     chunklimit = limit;
  350.  
  351.       QUIT;
  352.  
  353.       (* ac->ac_write_chunk_function) (data, chunklimit, ac);
  354.       data = chunklimit;
  355.     }
  356. }
  357.  
  358. static void
  359. drain_audio_port (ac)
  360.      AudioContext ac;
  361. {
  362.   while (ALgetfilled (ac->ac_port) > 0)
  363.     sginap(1);
  364. }
  365.  
  366. /* Methods to write a "chunk" from a buffer containing audio data to
  367.    an audio port.  This may involve some conversion if the output
  368.    device doesn't directly support the format the audio data is in. */
  369.  
  370. #if HAVE_MULAW_8
  371.  
  372. #if USE_MULAW_DECODE_TABLE
  373. #include "libst.h"
  374. #else /* not USE_MULAW_DECODE_TABLE */
  375. static int
  376. st_ulaw_to_linear (u)
  377.      int u;
  378. {
  379.   static CONST short table[] = {0,132,396,924,1980,4092,8316,16764};
  380.   int u1 = ~u;
  381.   short exponent = (u1 >> 4) & 0x07;
  382.   int mantissa = u1 & 0x0f;
  383.   int unsigned_result = table[exponent]+(mantissa << (exponent+3));
  384.   return u1 & 0x80 ? -unsigned_result : unsigned_result;
  385. }
  386. #endif /* not USE_MULAW_DECODE_TABLE */
  387.  
  388. static void
  389. write_mulaw_8_chunk (buffer, chunklimit, ac)
  390.      void * buffer;
  391.      void * chunklimit;
  392.      AudioContext ac;
  393. {
  394.   unsigned char * data = (unsigned char *) buffer;
  395.   unsigned char * limit = (unsigned char *) chunklimit;
  396.   short * obuf, * bufp;
  397.   long n_samples = limit - data;
  398.  
  399.   obuf = alloca (n_samples * sizeof (short));
  400.   bufp = &obuf[0];
  401.  
  402.   while (data < limit)
  403.     *bufp++ = st_ulaw_to_linear (*data++);
  404.   ALwritesamps (ac->ac_port, obuf, n_samples);
  405. }
  406. #endif /* HAVE_MULAW_8 */
  407.  
  408. #if HAVE_LINEAR
  409. static void
  410. write_linear_chunk (data, limit, ac)
  411.      void * data;
  412.      void * limit;
  413.      AudioContext ac;
  414. {
  415.   unsigned n_samples;
  416.  
  417.   switch (ac->ac_format)
  418.     {
  419.     case AFlinear16: n_samples = (short *) limit - (short *) data; break;
  420.     case AFlinear8:  n_samples =  (char *) limit -  (char *) data; break;
  421.     default: n_samples =  (long *) limit -  (long *) data; break;
  422.     }
  423.   ALwritesamps (ac->ac_port, data, (long) n_samples);
  424. }
  425.  
  426. #if HAVE_LINEAR_32
  427. static void
  428. write_linear_32_chunk (buffer, chunklimit, ac)
  429.      void * buffer;
  430.      void * chunklimit;
  431.      AudioContext ac;
  432. {
  433.   long * data = (long *) buffer;
  434.   long * limit = (long *) chunklimit;
  435.   long * obuf, * bufp;
  436.   long n_samples = limit-data;
  437.  
  438.   obuf = alloca (n_samples * sizeof (long));
  439.   bufp = &obuf[0];
  440.  
  441.   while (data < limit)
  442.     *bufp++ = *data++ >> 8;
  443.   ALwritesamps (ac->ac_port, obuf, n_samples);
  444. }
  445. #endif /* HAVE_LINEAR_32 */
  446. #endif /* HAVE_LINEAR */
  447.  
  448. static AudioContext
  449. initialize_audio_port (desc)
  450.      AudioContext desc;
  451. {
  452.   /* we can't use the same port for mono and stereo */
  453.   static AudioContextRec mono_port_state
  454.     = { { 0, 0, 0, 0 },
  455.     { (ALport) 0, AFunknown, 1, 0 },
  456.     { (void *) 0, (unsigned long) 0 } };
  457. #if HAVE_STEREO
  458.   static AudioContextRec stereo_port_state
  459.     = { { 0, 0, 0, 0 },
  460.     { (ALport) 0, AFunknown, 2, 0 },
  461.     { (void *) 0, (unsigned long) 0 } };
  462.   static AudioContext return_ac;
  463.  
  464.   switch (desc->ac_nchan)
  465.     {
  466.     case 1:  return_ac = & mono_port_state; break;
  467.     case 2:  return_ac = & stereo_port_state; break;
  468.     default: return (AudioContext) 0;
  469.     }
  470. #else /* not HAVE_STEREO */
  471.   static AudioContext return_ac = & mono_port_state;
  472. #endif /* not HAVE_STEREO */
  473.  
  474.   return_ac->device = desc->device;
  475.   return_ac->buffer = desc->buffer;
  476.   return_ac->ac_format = desc->ac_format;
  477.   return_ac->ac_queue_size = desc->ac_queue_size;
  478.  
  479.   if (return_ac->ac_port==(ALport) 0)
  480.     {
  481.       if ((open_audio_port (return_ac, desc))==-1)
  482.     {
  483.       report_file_error ("Open audio port", Qnil);
  484.       return (AudioContext) 0;
  485.     }
  486.     }
  487.   else
  488.     {
  489.       ALconfig config = ALgetconfig (return_ac->ac_port);
  490.       int changed = 0;
  491.       long params[2];
  492.  
  493.       params[0] = AL_OUTPUT_RATE;
  494.       ALgetparams (return_ac->ac_device, params, 2);
  495.       return_ac->ac_output_rate = params[1];
  496.  
  497.       if (return_ac->ac_output_rate != desc->ac_output_rate)
  498.     {
  499.       return_ac->ac_output_rate = params[1] = desc->ac_output_rate;
  500.       ALsetparams (return_ac->ac_device, params, 2);
  501.     }
  502.       if ((changed = set_output_format (config, return_ac->ac_format))==-1)
  503.     return (AudioContext) 0;
  504.       return_ac->ac_format = desc->ac_format;
  505.       if (changed)
  506.     ALsetconfig (return_ac->ac_port, config);
  507.     }
  508.   return_ac->ac_write_chunk_function = desc->ac_write_chunk_function;
  509.   get_current_volumes (& return_ac->device);
  510.   if (return_ac->ac_left_speaker_gain != desc->ac_left_speaker_gain
  511.       || return_ac->ac_right_speaker_gain != desc->ac_right_speaker_gain)
  512.     adjust_audio_volume (& desc->device);
  513.   return return_ac;
  514. }
  515.  
  516. static int
  517. open_audio_port (return_ac, desc)
  518.      AudioContext return_ac;
  519.      AudioContext desc;
  520. {
  521.   ALconfig config = ALnewconfig();
  522.   long params[2];
  523.  
  524.   adjust_audio_volume (& desc->device);
  525.   return_ac->ac_left_speaker_gain = desc->ac_left_speaker_gain;
  526.   return_ac->ac_right_speaker_gain = desc->ac_right_speaker_gain;
  527.   params[0] = AL_OUTPUT_RATE;
  528.   params[1] = desc->ac_output_rate;
  529.   ALsetparams (desc->ac_device, params, 2);
  530.   return_ac->ac_output_rate = desc->ac_output_rate;
  531.   if (set_channels (config, desc->ac_nchan)==-1)
  532.     return -1;
  533.   return_ac->ac_nchan = desc->ac_nchan;
  534.   if (set_output_format (config, desc->ac_format)==-1)
  535.     return -1;
  536.   return_ac->ac_format = desc->ac_format;
  537.   ALsetqueuesize (config, (long) CHUNKSIZE);
  538.   return_ac->ac_port = ALopenport("XEmacs audio output", "w", config);
  539.   ALfreeconfig (config);
  540.   if (return_ac->ac_port==0)
  541.     {
  542.       report_file_error ("Opening audio output port", Qnil);
  543.       return -1;
  544.     }
  545.   return 0;
  546. }
  547.  
  548. static int
  549. set_channels (config, nchan)
  550.      ALconfig config;
  551.      unsigned nchan;
  552. {
  553.   switch (nchan)
  554.     {
  555.     case 1: ALsetchannels (config, AL_MONO); break;
  556. #if HAVE_STEREO
  557.     case 2: ALsetchannels (config, AL_STEREO); break;
  558. #endif /* HAVE_STEREO */
  559.     default:
  560.       report_file_error ("Unsupported channel count",
  561.              Fcons (make_number (nchan), Qnil));
  562.       return -1;
  563.     }
  564.   return 0;
  565. }
  566.  
  567. static int
  568. set_output_format (config, format)
  569.      ALconfig config;
  570.      AudioFormat format;
  571. {
  572.   long samplesize;
  573.   long old_samplesize;
  574.  
  575.   switch (format)
  576.     {
  577. #if HAVE_MULAW_8
  578.     case AFmulaw8:
  579. #endif
  580. #if HAVE_LINEAR
  581.     case AFlinear16:
  582. #endif
  583. #if HAVE_MULAW_8 || HAVE_LINEAR
  584.       samplesize = AL_SAMPLE_16;
  585.       break;
  586. #endif
  587. #if HAVE_LINEAR
  588.     case AFlinear8:
  589.       samplesize = AL_SAMPLE_8;
  590.       break;
  591.     case AFlinear24:
  592. #if HAVE_LINEAR_32
  593.     case AFlinear32:
  594.       samplesize = AL_SAMPLE_24;
  595.       break;
  596. #endif
  597. #endif
  598.     default:
  599.       report_file_error ("Unsupported audio format",
  600.              Fcons (make_number (format), Qnil));
  601.       return -1;
  602.     }
  603.   old_samplesize = ALgetwidth (config);
  604.   if (old_samplesize==samplesize)
  605.     return 0;
  606.   ALsetwidth (config, samplesize);
  607.   return 1;
  608. }
  609.  
  610. static void
  611. adjust_audio_volume (device)
  612.      AudioDevice device;
  613. {
  614.   long params[4];
  615.   params[0] = AL_LEFT_SPEAKER_GAIN;
  616.   params[1] = device->left_speaker_gain;
  617.   params[2] = AL_RIGHT_SPEAKER_GAIN;
  618.   params[3] = device->right_speaker_gain;
  619.   ALsetparams (device->device, params, 4);
  620. }
  621.  
  622. static void
  623. get_current_volumes (device)
  624.      AudioDevice device;
  625. {
  626.   long params[4];
  627.   params[0] = AL_LEFT_SPEAKER_GAIN;
  628.   params[2] = AL_RIGHT_SPEAKER_GAIN;
  629.   ALgetparams (device->device, params, 4);
  630.   device->left_speaker_gain = params[1];
  631.   device->right_speaker_gain = params[3];
  632. }
  633.  
  634. #if HAVE_SND_FILES
  635.  
  636. /* Parsing .snd (NeXT/Sun) headers */
  637.  
  638. typedef struct
  639. {
  640.   int magic;
  641.   int dataLocation;
  642.   int dataSize;
  643.   int dataFormat;
  644.   int samplingRate;
  645.   int channelCount;
  646.   char info[4];
  647. }
  648. SNDSoundStruct;
  649. #define SOUND_TO_HOST_INT(x) ntohl(x)
  650.  
  651. typedef enum
  652. {
  653.   SND_FORMAT_FORMAT_UNSPECIFIED,
  654.   SND_FORMAT_MULAW_8,
  655.   SND_FORMAT_LINEAR_8,
  656.   SND_FORMAT_LINEAR_16,
  657.   SND_FORMAT_LINEAR_24,
  658.   SND_FORMAT_LINEAR_32,
  659.   SND_FORMAT_FLOAT,
  660.   SND_FORMAT_DOUBLE,
  661.   SND_FORMAT_INDIRECT,
  662.   SND_FORMAT_NESTED,
  663.   SND_FORMAT_DSP_CODE,
  664.   SND_FORMAT_DSP_DATA_8,
  665.   SND_FORMAT_DSP_DATA_16,
  666.   SND_FORMAT_DSP_DATA_24,
  667.   SND_FORMAT_DSP_DATA_32,
  668.   SND_FORMAT_DSP_unknown_15,
  669.   SND_FORMAT_DISPLAY,
  670.   SND_FORMAT_MULAW_SQUELCH,
  671.   SND_FORMAT_EMPHASIZED,
  672.   SND_FORMAT_COMPRESSED,
  673.   SND_FORMAT_COMPRESSED_EMPHASIZED,
  674.   SND_FORMAT_DSP_COMMANDS,
  675.   SND_FORMAT_DSP_COMMANDS_SAMPLES
  676. }
  677. SNDFormatCode;
  678.  
  679. static int
  680. parse_snd_header (header, length, desc)
  681.      void * header;
  682.      long length;
  683.      AudioContext desc;
  684. {
  685. #define hp ((SNDSoundStruct *) (header))
  686.   long limit;
  687.  
  688. #if HAVE_LINEAR
  689.   desc->ac_write_chunk_function = write_linear_chunk;
  690. #endif
  691.   switch ((SNDFormatCode) SOUND_TO_HOST_INT (hp->dataFormat))
  692.     {
  693. #if HAVE_MULAW_8
  694.     case SND_FORMAT_MULAW_8:
  695.       desc->ac_format = AFmulaw8;
  696.       desc->ac_write_chunk_function = write_mulaw_8_chunk;
  697.       break;
  698. #endif
  699. #if HAVE_LINEAR
  700.     case SND_FORMAT_LINEAR_8:
  701.       desc->ac_format = AFlinear8;
  702.       break;
  703.     case SND_FORMAT_LINEAR_16:
  704.       desc->ac_format = AFlinear16;
  705.       break;
  706.     case SND_FORMAT_LINEAR_24:
  707.       desc->ac_format = AFlinear24;
  708.       break;
  709. #endif
  710. #if HAVE_LINEAR_32
  711.     case SND_FORMAT_LINEAR_32:
  712.       desc->ac_format = AFlinear32;
  713.       desc->ac_write_chunk_function = write_linear_32_chunk;
  714.       break;
  715. #endif
  716.     default:
  717.       desc->ac_format = AFunknown;
  718.     }
  719.   desc->ac_output_rate = SOUND_TO_HOST_INT (hp->samplingRate);
  720.   desc->ac_nchan = SOUND_TO_HOST_INT (hp->channelCount);
  721.   desc->ac_data = (char *) header + SOUND_TO_HOST_INT (hp->dataLocation);
  722.   limit = (char *) header + length - (char *) desc->ac_data;
  723.   desc->ac_size = SOUND_TO_HOST_INT (hp->dataSize);
  724.   if (desc->ac_size > limit) desc->ac_size = limit;
  725.   return 0;
  726. #undef hp
  727. }
  728. #endif /* HAVE_SND_FILES */
  729.  
  730.